var _Node = require('component/node.js');
var _inherit = require('core/inherit.js');
var _global = require('global/global.js');
var _geometry = require('core/glm.js');
var _vec3 = _geometry.vec3f;

var S = require('res/style.js');
var _Constant = require('scenes/game/constant.js');
var _Skins = require('scenes/game/cellcommon.js');
var TWEEN = require('third_party/tweenjs/tween.js');
var _Helper = require('third_party/tweenjs/helper.js');

var HALF_THICKNESS = 5;

// ==========================
// Front face and backface
// ==========================
function Face(under, text) {
    _Node.call(this);
    this.mLayers = Array.prototype.slice.call(arguments, 0);
    this.mBack = false;
}
_inherit(Face, _Node);
Face.prototype.setFlip = function (degree, offset, scale) {
    this.mBack = degree > 90;
    this.setOffset(offset, 0);
    this.setScale(scale, 1);
    this.touchMatrix();
};
Face.prototype.draw = function (context) {
    context.pushMatrix(this.mMatrix);
    if (this.mBack) {
        this.mLayers[0].draw(context);
    } else {
        for (var i = 0; i < this.mLayers.length; i++) {
            this.mLayers[i].draw(context);
        }
    }
    context.popMatrix();
};

// ==========================
// Card makeup of front and back
// ==========================
function Card(front, under) {
    this.mFront = front;
    this.mUnder = under;
    this.mBack = false;
}
Card.prototype.setFlip = function (degree) {
    this.mBack = degree > 90;
    var r = degree * Math.PI / 180;
    var offset = Math.sin(r) * HALF_THICKNESS;
    var scale = Math.cos(r);
    this.mFront.setFlip(degree, -offset, scale);
    this.mUnder.setFlip(180 - degree, offset, -scale);
};
Card.prototype.draw = function (context) {
    if (this.mBack) {
        this.mFront.draw(context);
        this.mUnder.draw(context);
    } else {
        this.mUnder.draw(context);
        this.mFront.draw(context);
    }
};

// ==========================
// Cell
// ==========================
var STATE_NORMAL = 0;
var STATE_MERGING = 1;

var multip = 8;
var SPEED_1 = 30 * multip;
var SPEED_2 = 15 * multip;
var BOUNCE_TIME = 2 / multip;

/**
 * @param count of this cell
 * @constructor
 */
function Cell(count) {
    _Node.call(this);

    this.mCount = count;
    this.mPreCount = count;
    this.mIsTop = false;
    this.mCheck = 0;

    this.mStatus = STATE_NORMAL;
    this.setSize(_Constant.cellSize);
    this.setAnchor(0.5, 0.5);
    _Constant.cellSize.scale(0.5, this.mDrawCenter = new _vec3());

    // skin
    this.mSkin = _Skins.createSkin(count);
    this.mSkin.setPosition(0, -1);
    this.mBackSkin = _Skins.createSkin(count);
    this.mBackSkin.setPosition(0, -1);
    this.mText = _Skins.createText(count);
    this.mText.setPosition(0, 5);

    // front face
    this.mFront = new Face(this.mSkin, this.mText);
    this.mFront.setPosition(this.mDrawCenter);
    this.mFront.setFlip(0, 0, 1);
    this.mBack = new Face(this.mBackSkin, this.mText);
    this.mBack.setPosition(this.mDrawCenter);
    this.mCard = new Card(this.mFront, this.mBack);

    this.mPoint = _Helper.createPoint();
    this.mPoint.setDirection(0, 1);
    this.mPoint.setPosition(this.mDrawCenter);

    this.mStartSpeed = SPEED_1;
    this.speed = SPEED_1;
    this.time = 0;
    this.mBounceAnima = new TWEEN.Tween(this)
        .to({speed: -SPEED_1, time: BOUNCE_TIME}, BOUNCE_TIME)
        .onUpdate(this.onBounceUpdate)
        .onComplete(function () {
            this.mStartSpeed = SPEED_2;
            this.speed = SPEED_2;
            this.time = 0;
        })
        .chain(new TWEEN.Tween(this)
            .to({speed: -SPEED_2, time: BOUNCE_TIME}, BOUNCE_TIME)
            .onUpdate(this.onBounceUpdate)
        );

    this.flip = 0;
    this.mFlipAnima = new TWEEN.Tween(this)
        .to({flip: 180}, 0.18)
        .onUpdate(this.onFlipUpdate)
        .onComplete(this.onFlipComplete);

    this.updateCount(count);
}
_inherit(Cell, _Node);

Cell.prototype.checkTop = function (top) {
    var istop = this.mIsTop;
    this.mIsTop = (this.mCount >= top);
    if (istop != this.mIsTop) {
        this.updateText(this.mCount);
    }

    if (this.mIsTop) {
        this.mStartSpeed = SPEED_1;
        this.speed = SPEED_1;
        this.time = 0;
        if (this.mCheck == 0) {
            this.mBounceAnima.delay(0);
        } else {
            this.mBounceAnima.delay(0.15);
        }
        this.mCheck++;
        this.mBounceAnima.start();
    }
};

// ---------------- reuse by a pool
Cell.prototype.onRelease = function () {
    this.mFlipAnima.stop();
    this.mBounceAnima.stop();
    return this;
};
/**
 * when reuse a pooled cell
 * @param count
 */
Cell.prototype.onInit = function (count) {
    this.mIsTop = false;
    this.mCheck = 0;
    this.mFront.setFlip(0, 0, 1);
    this.mStatus = STATE_NORMAL;
    this.updateCount(count);

    var pos = this.mPoint.getPosition(0);
    this.mFront.setPosition(pos);
    this.mFront.touchMatrix();
    this.mBack.setPosition(pos);
    this.mBack.touchMatrix();

    return this;
};

// ---------------- work with tween anima
Cell.prototype.onBounceUpdate = function () {
    var pos = this.mPoint.getPosition((this.mStartSpeed + this.speed) * 0.5 * this.time);
    this.mFront.setPosition(pos);
    this.mFront.touchMatrix();
    this.mBack.setPosition(pos);
    this.mBack.touchMatrix();
};

// ---------------- interact with gameover animation
/**
 * show gameover flip
 * @param delay
 * @returns {*}
 */
Cell.prototype.startFlip = function () {
    this.flip = 0;
    this.mStatus = STATE_MERGING;
    this.mSkin.updateSkin(this.mCount);
    this.mBackSkin.updateSkin(this.mCount);
    this.mCard.setFlip(0);
};
Cell.prototype.setFlip = function (degree) {
    this.flip = degree;
    this.onFlipUpdate();
};
Cell.prototype.endFlip = function (disable) {
    this.onFlipComplete();
    if (disable) {
        this.mSkin.setGray(true);
    }
};

/**
 * when two cell merge together
 * @param count
 */
Cell.prototype.startMerge = function (count) {
    this.mPreCount = this.mCount;
    this.mCheck = 0;

    // stop current flip anima
    if (this.mStatus == STATE_MERGING) {
        this.mFlipAnima.stop();
        this.onFlipComplete();
    }

    this.flip = 0;
    this.mCount = count;
    this.mStatus = STATE_MERGING;
    this.mSkin.updateSkin(this.mCount);
    this.mBackSkin.updateSkin(this.mCount);
    this.mCard.setFlip(0);
    this.mFlipAnima.start();
};
Cell.prototype.onFlipComplete = function () {
    this.updateText(this.mCount);
    this.mFront.setFlip(0, 0, 1);
    this.mStatus = STATE_NORMAL;
};
Cell.prototype.onFlipUpdate = function () {
    if (this.flip > 90 && this.mPreCount != this.mCount) {
        this.mPreCount = this.mCount;
        this.mSkin.updateSkin(this.mCount);
        this.mBackSkin.updateSkin(this.mCount);
        this.updateText(this.mCount);
    }
    this.mCard.setFlip(this.flip);
};

Cell.prototype.setDisable = function (disable) {
    this.mBackSkin.setGray(disable);
};
Cell.prototype.updateText = function (count) {
    this.mText.updateText(count, this.mIsTop);
};
Cell.prototype.updateCount = function (count) {
    this.mCount = count;
    this.updateText(count);
    this.mSkin.updateSkin(count);
    return this;
};
Cell.prototype.draw = function (context) {
    this.updateMatrix();
    context.pushMatrix(this.mMatrix);
    if (this.mStatus == STATE_NORMAL) {
        this.mFront.draw(context);
    } else {
        this.mCard.draw(context);
    }
    context.popMatrix();
};
Cell.prototype.getCount = function () {
    return this.mCount;
};
Cell.prototype.toString = function () {
    return '[' + this.mCount + ']';
};

module.exports = Cell;